`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    16:08:10 03/25/2014 
// Design Name: 
// Module Name:    TopModule 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module TopModule(dpad,action,baction,sstart,clk,rst, R, G, B, HS, VS);
	input clk,rst;
	input	[3:0] dpad;
	input	action, baction, sstart;	//sstart is the input from board, start is the debounced version
	output [2:0] R, G;
	output [1:0] B;
	output HS,VS;

	wire	pixel_clk,slow_clk;
	wire	up,down,left,right,a,b,start;
	wire [10:0] hcount,vcount;
	wire [9:0] X,Y,Xb,Yb;
	wire [9:0] Xsprite1, Ysprite1;
	wire [9:0] Xsprite2, Ysprite2;
	wire [9:0] Xsprite3, Ysprite3;
	wire [9:0] Xsprite4, Ysprite4;
	wire [9:0] Xsprite5, Ysprite5;
	wire [9:0] Xsprite6, Ysprite6;
	wire [9:0] Xsprite7, Ysprite7;
	wire [9:0] Xsprite8, Ysprite8;
	wire [9:0] Xpheonix, Ypheonix;

	wire	[7:0] splash_color,
					bg_tile,
					char_pixel,
					bullet_sprite,
					pheonix_sprite,
					sprite_color;
					
	wire	[11:0] 	tile_address,
						tile_address1,
						tile_address2,
						tile_address3,
						tile_address4,
						tile_address5,
						tile_address6,
						tile_address7,
						tile_address8;
	wire 	blank,
			splash_screen,
			bg_block,
			character,
			bullet,
			pheonix,
			sprite1,
			sprite2,
			sprite3,
			sprite4,
			sprite5,
			sprite6,
			sprite7,
			sprite8,
			an_enemy_sprite,
			HP_Bar_pheonix,
			HP_Bar_inverse,
			HP_Bar_Border,
			score_bar,
			score_border;

	wire	[7:0] respawn_time;

	wire scroll_en;
	wire HS,VS;
	wire walk_en;
	reg splash_en;
	reg bossIsEnabled;
	reg enemiesEnabled;
	
	wire ai_en1;
	wire ai_en2;
	wire ai_en3;
	wire ai_en4;
	wire ai_en5;
	wire ai_en6;
	wire ai_en7;
	wire ai_en8;

	clock_divider	PCLK(clk,rst,pixel_clk);
	slow_clock		SCLK(clk,rst,slow_clk);
	

	debouncer	A(action,clk,a);
	debouncer	BACTA(baction,clk,b);
	debouncer	UP(dpad[0],clk,up);
	debouncer	DOWN(dpad[1],clk,down);
	debouncer	LEFT(dpad[2],clk,left);
	debouncer	RIGHT(dpad[3],clk,right);
	debouncer	START(sstart,clk,start);

	vga_display DISPLAY(	splash_screen,splash_color,splash_border,
								bg_block,bg_tile,
								character,char_pixel,
								bullet,bullet_sprite,
								pheonix,pheonix_sprite,
								sprite1,sprite2,sprite3,sprite4,sprite5,sprite6,sprite7,sprite8,sprite_color,
								HP_Bar_pheonix,HP_Bar_inverse,HP_Bar_Border,
								score_bar,score_border,
								rst,pixel_clk,
								blank, R, G, B, HS, VS,hcount,vcount);

	start_screen	SS(splash_en,blank,hcount,vcount,pixel_clk,rst,splash_screen,splash_border,splash_color);
	background		BG(scroll_en,blank,hcount,vcount,HS,pixel_clk,rst,bg_block,bg_tile);
	player			WOMBAT(walk_en, X, Y,blank,hcount,vcount,pixel_clk,rst,character,char_pixel);
	projectile		LAZOR(Xb,Yb,blank,hcount,vcount,pixel_clk,rst,bullet,bullet_sprite);
	boss				DA_BOSS(bossIsEnabled, Xpheonix, Ypheonix,blank,hcount,vcount,pixel_clk,rst,pheonix,pheonix_sprite);

	enemy				CAT1(	walk_en, Xsprite1, Ysprite1,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address1,sprite1);

	enemy				CAT2(	walk_en, Xsprite2, Ysprite2,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address2,sprite2);

	enemy				CAT3(	walk_en, Xsprite3,Ysprite3,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address3,sprite3);

	enemy				CAT4(	walk_en, Xsprite4, Ysprite4,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address4,sprite4);	

	enemy				CAT5(	walk_en, Xsprite5, Ysprite5,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address5,sprite5);	

	enemy				CAT6(	walk_en, Xsprite6, Ysprite6,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address6,sprite6);
								
	enemy				CAT7(	walk_en, Xsprite7, Ysprite7,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address7,sprite7);
								
	enemy				CAT8(	walk_en, Xsprite8, Ysprite8,
								blank,hcount,vcount,pixel_clk,rst,
								tile_address8,sprite8);


	OneHotMux		MUX( 	tile_address1,
								tile_address2,
								tile_address3,
								tile_address4,
								tile_address5,
								tile_address6,
								tile_address7,
								tile_address8,
								{sprite1,sprite2,sprite3,sprite4,sprite5,sprite6,sprite7,sprite8},
								tile_address);

	catbot cat_bram(
		.clka(pixel_clk), // input clka
		.wea(1'b0), // input [0 : 0] wea
		.addra(tile_address), // input [15 : 0] addra
		.dina(8'd0), // input [7 : 0] dina
		.douta(sprite_color) // output [7 : 0] dout
	);
	
	pseudo_rand		LFSR(	clk, rst, 1'b1,  respawn_time);

	movement_ctrl	MVMNT(up,down,left,right,a,bullet,pheonix,an_enemy_sprite,VS,rst,clk,pixel_clk,X,Y,Xb,Yb);
	
	bot_control	#(56*1-16)	AI1(	ai_en1& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite1,Ysprite1);
	bot_control	#(56*2-16)	AI2(	ai_en2& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite2,Ysprite2);
	bot_control	#(56*3-16)	AI3(	ai_en3& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite3,Ysprite3);
	bot_control	#(56*4-16)	AI4(	ai_en4& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite4,Ysprite4);
	bot_control	#(56*5-16)	AI5(	ai_en5& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite5,Ysprite5);
	bot_control	#(56*6-16)	AI6(	ai_en6& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite6,Ysprite6);
	bot_control	#(56*7-16)	AI7(	ai_en7& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite7,Ysprite7);
	bot_control	#(56*8-16)	AI8(	ai_en8& enemiesEnabled,respawn_time,VS,clk,slow_clk,rst,Xsprite8,Ysprite8);
	
	boss_control	AI_BOSS(clk,slow_clk,rst,VS,Xpheonix,Ypheonix);
	
	status_bars HP(	bullet,pheonix,character,
							sprite1,sprite2,sprite3,sprite4,sprite5,sprite6,sprite7,sprite8,
							ai_en1,ai_en2,ai_en3,ai_en4,ai_en5,ai_en6,ai_en7,ai_en8,
							blank,hcount,vcount,clk,rst,
							HP_Bar_pheonix,HP_Bar_inverse,HP_Bar_Border,
							boss_enable,splash_enable,reset_score,score_off,hp_off,
							score_bar,score_border);
	initial begin
		splash_en <= 1'b1;
		bossIsEnabled <= 1'b0;
		enemiesEnabled <= 1'b0;
		score_to_zero <= 1'b0;
		score_bar_off <= 1'b1;
		hp_bar_off <= 1'b1;
		state <= 0;
		nextstate <=0;
	end

	reg score_to_zero, score_bar_off, hp_bar_off;
	reg [2:0] state, nextstate;
	
	assign reset_score = score_to_zero;
	assign score_off = score_bar_off;
	assign hp_off = hp_bar_off;


///////////////////////////////////////////////////////////////////
// Begin Finite State Machine
// State 0: splash screen is up, no enemies, background doesnt scroll
// State 1: splash off, enemies spawn, no boss yet
// State 2: splash off, enemies stop spawning fighting boss!
	always @ (posedge clk) begin
		if(rst) begin
			state <= 3'b0;
		end else begin
			state <= nextstate;
		end
	end

	always @ (posedge clk) begin
		if(rst) begin
			nextstate <= 3'b0;
		end else if(start) begin
			nextstate <= 3'b1;
		end else if(boss_enable) begin
			nextstate <= 3'b10;
		end else if(splash_enable) begin
			nextstate <= 3'b0;
		end else begin
			nextstate <= state;
		end
	end
	// when is splash enabled?
	always @ (posedge clk) begin
		if(rst) begin
			splash_en <= 1'b1;
		end else if(state == 0) begin
			splash_en <= 1'b1;
		end else begin
			splash_en <= 1'b0;
		end
	end
	// when is boss enabled?
	always @ (posedge clk) begin
		if(rst) begin
			bossIsEnabled <= 1'b0;
		end else if(state == 2) begin
			bossIsEnabled <= 1'b1;
		end else if(boss_enable) begin
			bossIsEnabled <= 1'b1;
		end else begin
			bossIsEnabled <= 1'b0;
		end
	end
	// when does the users score need to be reset?
	always @ (posedge clk) begin
		if(rst) begin
			score_to_zero <= 1'b0;
		end else if(state == 0) begin
			score_to_zero <= 1'b1;
		end else begin
			score_to_zero <= 1'b0;
		end
	end
	
	always @ (posedge clk) begin
		if(rst) begin
			enemiesEnabled <= 1'b0;
		end else if(state == 1) begin
			enemiesEnabled <= 1'b1;
		end else begin
			enemiesEnabled <= 1'b0;
		end
	end
	// hp and score bars are disabled when in splash screen
	always @ (posedge clk) begin
		if(rst) begin
			hp_bar_off <= 1'b1;
		end else if(state == 2) begin
			hp_bar_off <= 1'b0;
		end else begin
			hp_bar_off <= 1'b1;
		end
	end
	
	always @ (posedge clk) begin
		if(rst) begin
			score_bar_off <= 1'b1;
		end else if(state == 0) begin
			score_bar_off <= 1'b1;
		end else begin
			score_bar_off <= 1'b0;
		end
	end
	
	// End Finite State Machine
	///////////////////////////////////////////////////////////////////

	assign scroll_en = ~splash_en;
	assign walk_en = 1'b1;
	
	assign an_enemy_sprite = sprite1 | sprite2 | sprite3 | sprite4 | sprite5 | sprite6 | sprite7 | sprite8;

endmodule
